package com.example.performance.statistics;

import com.example.performance.model.LoadTestConfig;
import com.example.performance.model.TestReport;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * 测试报告生成器
 * 负责生成不同格式的测试报告
 */
public class ReportGenerator {

    private static final Logger logger = LoggerFactory.getLogger(ReportGenerator.class);

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 生成测试报告
     * 
     * @param report 测试报告数据
     * @param config 测试配置
     */
    public void generateReport(TestReport report, LoadTestConfig config) {
        if (report == null) {
            logger.error("测试报告为空，无法生成报告");
            return;
        }

        logger.info("生成测试报告: 格式={}, 输出路径={}", config.getReportFormat(), config.getOutputPath());

        try {
            switch (config.getReportFormat()) {
                case CONSOLE:
                    printConsoleReport(report);
                    break;
                case JSON:
                    generateJsonReport(report, config.getOutputPath());
                    break;
                case HTML:
                    generateHtmlReport(report, config.getOutputPath());
                    break;
                case CSV:
                    generateCsvReport(report, config.getOutputPath());
                    break;
                default:
                    logger.warn("不支持的报告格式: {}, 使用控制台输出", config.getReportFormat());
                    printConsoleReport(report);
                    break;
            }
        } catch (Exception e) {
            logger.error("生成报告失败", e);
            // 如果指定格式失败，至少输出控制台报告
            printConsoleReport(report);
        }
    }

    /**
     * 控制台输出报告
     * 
     * @param report 测试报告
     */
    public void printConsoleReport(TestReport report) {
        System.out.println();
        System.out.println("========================================");
        System.out.println("           HTTP 性能测试报告");
        System.out.println("========================================");
        System.out.println("测试名称: " + report.getTestName());
        System.out.println("测试开始: " + formatTime(report.getTestStartTime()));
        System.out.println("测试结束: " + formatTime(report.getTestEndTime()));
        System.out.println("测试耗时: " + formatDuration(report.getTestDuration()));
        System.out.println();

        System.out.println("========== 基础统计 ==========");
        System.out.printf("总请求数:       %,d%n", report.getTotalRequests());
        System.out.printf("成功请求数:     %,d%n", report.getSuccessRequests());
        System.out.printf("失败请求数:     %,d%n", report.getFailedRequests());
        System.out.printf("成功率:         %.2f%%%n", report.getSuccessRate());
        System.out.println();

        System.out.println("========== 性能指标 ==========");
        System.out.printf("QPS (每秒请求): %.2f%n", report.getQps());
        System.out.printf("TPS (成功事务): %.2f%n", report.getTps());
        System.out.println();

        System.out.println("========== 响应时间统计 ==========");
        System.out.printf("最小响应时间:   %,d ms%n", report.getMinResponseTime());
        System.out.printf("最大响应时间:   %,d ms%n", report.getMaxResponseTime());
        System.out.printf("平均响应时间:   %.2f ms%n", report.getAvgResponseTime());
        System.out.printf("95%%分位响应时间: %,d ms%n", report.getP95ResponseTime());
        System.out.printf("99%%分位响应时间: %,d ms%n", report.getP99ResponseTime());
        System.out.println();

        // 状态码统计
        if (!report.getStatusCodeStats().isEmpty()) {
            System.out.println("========== 状态码分布 ==========");
            for (Map.Entry<Integer, Integer> entry : report.getStatusCodeStats().entrySet()) {
                double percentage = (double) entry.getValue() / report.getTotalRequests() * 100;
                System.out.printf("HTTP %d:        %,d (%.2f%%)%n",
                        entry.getKey(), entry.getValue(), percentage);
            }
            System.out.println();
        }

        // 错误统计
        if (!report.getErrorStats().isEmpty()) {
            System.out.println("========== 错误统计 ==========");
            for (Map.Entry<String, Integer> entry : report.getErrorStats().entrySet()) {
                double percentage = (double) entry.getValue() / report.getTotalRequests() * 100;
                System.out.printf("%-30s: %,d (%.2f%%)%n",
                        entry.getKey(), entry.getValue(), percentage);
            }
            System.out.println();
        }

        System.out.println("========================================");
    }

    /**
     * 生成JSON格式报告
     * 
     * @param report     测试报告
     * @param outputPath 输出路径
     */
    public void generateJsonReport(TestReport report, String outputPath) throws IOException {
        String fileName = generateFileName(outputPath, "json");
        logger.info("生成JSON报告: {}", fileName);

        objectMapper.writerWithDefaultPrettyPrinter().writeValue(new File(fileName), report);
        logger.info("JSON报告生成成功: {}", fileName);
    }

    /**
     * 生成HTML格式报告
     * 
     * @param report     测试报告
     * @param outputPath 输出路径
     */
    public void generateHtmlReport(TestReport report, String outputPath) throws IOException {
        String fileName = generateFileName(outputPath, "html");
        logger.info("生成HTML报告: {}", fileName);

        String htmlContent = generateHtmlContent(report);

        try (FileWriter writer = new FileWriter(fileName)) {
            writer.write(htmlContent);
        }

        logger.info("HTML报告生成成功: {}", fileName);
    }

    /**
     * 生成CSV格式报告
     * 
     * @param report     测试报告
     * @param outputPath 输出路径
     */
    public void generateCsvReport(TestReport report, String outputPath) throws IOException {
        String fileName = generateFileName(outputPath, "csv");
        logger.info("生成CSV报告: {}", fileName);

        try (FileWriter writer = new FileWriter(fileName)) {
            // CSV头部
            writer.write("请求名称,请求方法,请求URL,开始时间,结束时间,响应时间(ms),状态码,是否成功,错误信息,响应大小(字节),线程名\n");

            // CSV数据行
            for (com.example.performance.model.RequestResult result : report.getResults()) {
                writer.write(String.format("%s,%s,%s,%s,%s,%d,%d,%s,%s,%d,%s\n",
                        escapeCsv(result.getRequestName()),
                        escapeCsv(result.getMethod()),
                        escapeCsv(result.getUrl()),
                        formatTime(result.getStartTime()),
                        formatTime(result.getEndTime()),
                        result.getResponseTime(),
                        result.getStatusCode(),
                        result.isSuccess(),
                        escapeCsv(result.getErrorMessage()),
                        result.getResponseSize(),
                        escapeCsv(result.getThreadName())));
            }
        }

        logger.info("CSV报告生成成功: {}", fileName);
    }

    /**
     * 生成HTML内容
     * 
     * @param report 测试报告
     * @return HTML内容字符串
     */
    private String generateHtmlContent(TestReport report) {
        StringBuilder html = new StringBuilder();

        html.append("<!DOCTYPE html>\n");
        html.append("<html lang=\"zh-CN\">\n");
        html.append("<head>\n");
        html.append("    <meta charset=\"UTF-8\">\n");
        html.append("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
        html.append("    <title>HTTP性能测试报告 - ").append(report.getTestName()).append("</title>\n");
        html.append("    <style>\n");
        html.append("        body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }\n");
        html.append(
                "        .container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n");
        html.append("        h1, h2 { color: #333; border-bottom: 2px solid #4CAF50; padding-bottom: 10px; }\n");
        html.append(
                "        .summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin: 20px 0; }\n");
        html.append(
                "        .metric { background: #f8f9fa; padding: 15px; border-radius: 5px; border-left: 4px solid #4CAF50; }\n");
        html.append("        .metric-title { font-weight: bold; color: #666; font-size: 14px; }\n");
        html.append("        .metric-value { font-size: 24px; font-weight: bold; color: #333; margin-top: 5px; }\n");
        html.append("        table { width: 100%; border-collapse: collapse; margin: 20px 0; }\n");
        html.append("        th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }\n");
        html.append("        th { background-color: #4CAF50; color: white; }\n");
        html.append("        .success { color: #4CAF50; }\n");
        html.append("        .error { color: #f44336; }\n");
        html.append("        .timestamp { color: #666; font-size: 14px; }\n");
        html.append("    </style>\n");
        html.append("</head>\n");
        html.append("<body>\n");
        html.append("    <div class=\"container\">\n");

        // 标题和基本信息
        html.append("        <h1>HTTP性能测试报告</h1>\n");
        html.append("        <p><strong>测试名称:</strong> ").append(report.getTestName()).append("</p>\n");
        html.append("        <p class=\"timestamp\"><strong>测试开始:</strong> ")
                .append(formatTime(report.getTestStartTime())).append("</p>\n");
        html.append("        <p class=\"timestamp\"><strong>测试结束:</strong> ")
                .append(formatTime(report.getTestEndTime())).append("</p>\n");
        html.append("        <p class=\"timestamp\"><strong>测试耗时:</strong> ")
                .append(formatDuration(report.getTestDuration())).append("</p>\n");

        // 关键指标摘要
        html.append("        <h2>关键指标摘要</h2>\n");
        html.append("        <div class=\"summary\">\n");
        html.append("            <div class=\"metric\">\n");
        html.append("                <div class=\"metric-title\">总请求数</div>\n");
        html.append("                <div class=\"metric-value\">")
                .append(String.format("%,d", report.getTotalRequests())).append("</div>\n");
        html.append("            </div>\n");
        html.append("            <div class=\"metric\">\n");
        html.append("                <div class=\"metric-title\">成功率</div>\n");
        html.append("                <div class=\"metric-value")
                .append(report.getSuccessRate() >= 95 ? " success" : " error").append("\">")
                .append(String.format("%.2f%%", report.getSuccessRate())).append("</div>\n");
        html.append("            </div>\n");
        html.append("            <div class=\"metric\">\n");
        html.append("                <div class=\"metric-title\">平均响应时间</div>\n");
        html.append("                <div class=\"metric-value\">")
                .append(String.format("%.2f ms", report.getAvgResponseTime())).append("</div>\n");
        html.append("            </div>\n");
        html.append("            <div class=\"metric\">\n");
        html.append("                <div class=\"metric-title\">QPS</div>\n");
        html.append("                <div class=\"metric-value\">").append(String.format("%.2f", report.getQps()))
                .append("</div>\n");
        html.append("            </div>\n");
        html.append("        </div>\n");

        // 响应时间统计
        html.append("        <h2>响应时间统计</h2>\n");
        html.append("        <table>\n");
        html.append("            <tr><th>指标</th><th>值 (毫秒)</th></tr>\n");
        html.append("            <tr><td>最小响应时间</td><td>").append(String.format("%,d", report.getMinResponseTime()))
                .append("</td></tr>\n");
        html.append("            <tr><td>最大响应时间</td><td>").append(String.format("%,d", report.getMaxResponseTime()))
                .append("</td></tr>\n");
        html.append("            <tr><td>平均响应时间</td><td>").append(String.format("%.2f", report.getAvgResponseTime()))
                .append("</td></tr>\n");
        html.append("            <tr><td>95%分位响应时间</td><td>").append(String.format("%,d", report.getP95ResponseTime()))
                .append("</td></tr>\n");
        html.append("            <tr><td>99%分位响应时间</td><td>").append(String.format("%,d", report.getP99ResponseTime()))
                .append("</td></tr>\n");
        html.append("        </table>\n");

        // 状态码分布
        if (!report.getStatusCodeStats().isEmpty()) {
            html.append("        <h2>状态码分布</h2>\n");
            html.append("        <table>\n");
            html.append("            <tr><th>状态码</th><th>次数</th><th>百分比</th></tr>\n");
            for (Map.Entry<Integer, Integer> entry : report.getStatusCodeStats().entrySet()) {
                double percentage = (double) entry.getValue() / report.getTotalRequests() * 100;
                html.append("            <tr><td>HTTP ").append(entry.getKey()).append("</td><td>")
                        .append(String.format("%,d", entry.getValue())).append("</td><td>")
                        .append(String.format("%.2f%%", percentage)).append("</td></tr>\n");
            }
            html.append("        </table>\n");
        }

        html.append("        <p class=\"timestamp\">报告生成时间: ").append(formatTime(System.currentTimeMillis()))
                .append("</p>\n");
        html.append("    </div>\n");
        html.append("</body>\n");
        html.append("</html>\n");

        return html.toString();
    }

    /**
     * 生成文件名
     * 
     * @param outputPath 输出路径
     * @param extension  文件扩展名
     * @return 完整文件名
     */
    private String generateFileName(String outputPath, String extension) {
        File outputDir = new File(outputPath);
        if (!outputDir.exists()) {
            outputDir.mkdirs();
        }

        String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        return outputPath + File.separator + "performance_test_report_" + timestamp + "." + extension;
    }

    /**
     * 格式化时间
     * 
     * @param timestamp 时间戳
     * @return 格式化的时间字符串
     */
    private String formatTime(long timestamp) {
        if (timestamp <= 0)
            return "N/A";
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp));
    }

    /**
     * 格式化持续时间
     * 
     * @param duration 持续时间（毫秒）
     * @return 格式化的持续时间字符串
     */
    private String formatDuration(long duration) {
        if (duration <= 0)
            return "N/A";

        long hours = duration / (1000 * 60 * 60);
        long minutes = (duration % (1000 * 60 * 60)) / (1000 * 60);
        long seconds = (duration % (1000 * 60)) / 1000;

        if (hours > 0) {
            return String.format("%d小时%d分钟%d秒", hours, minutes, seconds);
        } else if (minutes > 0) {
            return String.format("%d分钟%d秒", minutes, seconds);
        } else {
            return String.format("%.2f秒", duration / 1000.0);
        }
    }

    /**
     * CSV字段转义
     * 
     * @param value 原始值
     * @return 转义后的值
     */
    private String escapeCsv(String value) {
        if (value == null)
            return "";
        if (value.contains(",") || value.contains("\"") || value.contains("\n")) {
            return "\"" + value.replace("\"", "\"\"") + "\"";
        }
        return value;
    }
}